<?php
/*
 *	Kris' Lightweight Framework (KLF)
 *
 *	@author Kristian Oye <kristianoye@gmail.com> 
 *	@copyright (C) 2010-2011, Kristian Oye
 */
namespace KLF\System
{
	use KLF\System\Errors\KReadOnlyException;

	final class KPropertyContext
	{
		const PROP_GET = 0;
		const PROP_SET = 1;
	}
	
	/**
	 *  Base object for all framework objects.
	 *
	 *  @package KLF\System
	 *  @access public
	 *  @author Kristian Oye <kristianoye@gmail.com>
	 *  @since 0.1
	 */
	class KObject implements IKObject
	{
		public function __construct()
		{
		}
		
		public function __destruct()
		{
			if (is_a($this, 'KLF\System\IDisposable'))
			{
				$this->Dispose();
			}
		}
		
		/**
		 * Alternate constructor (createInstance).  Used to allow method chaining.
		 * 
		 * @return KObject
		 */
		public static function NewInstance()
		{
			$class = new \ReflectionClass($className = get_called_class());
			$args = func_get_Args();
			
			if (count($args) === 1 && is_object($args[0]) && is_a($args[0], '\Closure'))
			{
				$o = $class->newInstance();
				$c = $args[0];
				$c($o);
				return $o;
			}
			else
				return $class->newInstanceArgs(func_get_args());
		}
		
		/**
		 * Returns the class name at the level which the method was called.
		 * 
		 * @return KType The class name
		 * @since 0.1
		 */
		public final static function GetType()
		{
			return KType::GetTypeByClass(get_called_class());
		}

		
		/**
		 * Magic getter that calls optional propGet gatekeeper method.  
		 * Properties must be defined using _prop naming convention.
		 * 
		 * @param string $name The property to fetch
		 * @since 0.1
		 * @return mixed
		 * 
		 * @throws Errors\KPropertyException
		 */
		public function __get($name)
		{
			if (property_exists(get_called_class(), $propName = "_prop$name"))
			{
				if (method_exists($this, $methodName = "propGet$name"))
				{
					return $this->$methodName(NULL, KPropertyContext::PROP_GET);
				}
				return $this->$propName;
			}
			elseif (property_exists(get_called_class(), $propName = "_rprop$name"))
			{
				if (method_exists($this, $methodName = "prop$name"))
				{
					return $this->$methodName(NULL, KPropertyContext::PROP_GET);
				}
				return $this->$propName;
			}
			elseif (method_exists($this, $methodName = "prop$name"))
			{
				return $this->$methodName(NULL, KPropertyContext::PROP_GET);
			}
			elseif (property_exists(get_called_class(), $propName = "_$name"))
			{
				return $this->$propName;
			}
			throw new Errors\KPropertyException($name, $this);
		}
		
		/**
		 * Magic setter that calls optional propGet gatekeeper method.  
		 * Properties must be defined using _prop naming convention.
		 * 
		 * @param string $name The property name to set
		 * @param mixed $value The value to set
		 * 
		 * @since 0.1
		 * @return mixed
		 * 
		 * @throws Errors\KPropertyException
		 */
		public function __set($name, $value)
		{
			if (property_exists(get_called_class(), $propName = "_prop$name"))
			{
				if (method_exists($this, $methodName = "prop$name"))
				{
					return $this->$methodName($value, KPropertyContext::PROP_SET);
				}
				return ($this->$propName = $value);
			}
			elseif (property_exists(get_called_class(), $propName = "_rprop$name"))
			{
				throw new KReadOnlyException('Property', $name);
			}
			elseif (method_exists($this, $methodName = "prop$name"))
			{
				return $this->$methodName($value, KPropertyContext::PROP_SET);
			}
			throw new Errors\KPropertyException($name, $this);
		}
				
		/**
		 * A simple string representation of the object.
		 * @return string
		 */
		public function __toString()
		{
			return get_called_class();
		}
	}
}
	